#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>

#include "tklog.h"
#include "tkclient.h"
#include "netutils.h"
#include "commproto.h"
#include "tkerror.h"
#include "proto.h"
#include "errno.h"

struct tk_client gEnv;

extern int after_connect_entry_impl(struct select_env *env, struct custom_socket *s);
extern int hd_input_message(struct select_env *env, struct custom_socket *s, int event_type);

static int earse_space(char *buffer)
{
        int i = 0, pos = 0;
        int len = strlen(buffer);

        for (i = 0; i < len; i++) {
                if (!(buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\r' || buffer[i] == '\n')) {
                        buffer[pos++] = buffer[i];
                }
        }
        buffer[pos] = '\0';

        return pos;
}

int tk_read_conf_file(struct tk_client *env)
{
	FILE *file = NULL;
	char buffer[201];
	int line_len;

	file = fopen("client.conf", "r");
	if (file == NULL) {
		fprintf(stderr, "read conf file failed");
		return -1;
	}
		
	while (fgets(buffer, 200, file) != NULL) {
		line_len = earse_space(buffer);	
		if (line_len <= 0) {
			continue;
		}

		if (strncmp("serverip=", buffer, sizeof("serverip=") - 1) == 0) {
			strcpy(gEnv.serverip, buffer + sizeof("serverip=") - 1);
		}
		else if (strncmp("serverport=", buffer, sizeof("serverport=") - 1) == 0) {
			gEnv.serverport = atoi(buffer + sizeof("serverport=") - 1);
		}
		else if (strncmp("clientname=", buffer, sizeof("clientname=") - 1) == 0) {
			strcpy(gEnv.clientname, buffer + sizeof("clientname=") - 1);
		}
		else if (strncmp("clientid=", buffer, sizeof("clientid=") - 1) == 0) {
			gEnv.clientid = atoi(buffer + sizeof("clientid=") - 1);
		}
	}
	strcpy(gEnv.cinfo.clientname, gEnv.clientname);
	gEnv.cinfo.clientid = gEnv.clientid;

	fprintf(stderr, "serverip[%s]:serverport[%d] - clientname[%s] - clientid[%d]\n", gEnv.serverip, 
											gEnv.serverport, 
											gEnv.clientname, 
											gEnv.clientid);

	fclose(file);

	return 0;
}

void set_local_addr_info(struct custom_socket *s)
{
	strcpy(gEnv.cinfo.ip, s->addr.ipv4);
}

int get_user_info(struct tk_message *tmsg)
{
	int r = 0;

	memset(tmsg, 0x00, sizeof(tmsg));
	SERIAL_TO_TK_MESSAGE(&gEnv.cinfo, tmsg, clientinfo, MSG_TYPE_CLIENT_INFO, r);
	if (r) {
		elog("build tk_message with clientinfo failed, r=[%d]", r);
		return -1;
	}

	TK_MESSAGE_INFO(tmsg);

	return TK_OK;
}

int do_put_message_to_sendsocket(char *message_content)
{
        struct tk_message tmsg;
        message msg;
        int r = 0;
	struct custom_socket *s = NULL;

	if (gEnv.conn == NULL) {
		elog("init global env connect");
		return TK_OK;
	}

	memset(&msg, 0x00, sizeof(msg));
	memset(&tmsg, 0x00, sizeof(tmsg));

        strcpy(msg.clientname, gEnv.clientname);
        msg.clientid = gEnv.clientid;
	strcpy(msg.content, message_content);

        SERIAL_TO_TK_MESSAGE(&msg, &tmsg, message, MSG_TYPE_COMM_MSG, r);
        if (r) {
                elog("build tk_message with message failed");
                return -1;
        }

	s = gEnv.conn->csock;
	r = tk_do_add_send_msg(s, &tmsg);
        if (r) {
                if (r == TK_NEED_ADD_W_EVENT) {
                        r = select_add_write_event(gEnv.select_env, gEnv.conn->csock->event);
                        if (r) {
                                elog("add read event failed\n");
                                return -1;
                       }
                }
                else {
                        elog(" add send message failed");
                        return -1;
                }
        }

	/* manual send */

	return TK_OK;	
}

int init_input_FD()
{
	struct custom_socket *s = NULL;

	/*  0 fd input */
	s = get_custom_socket(0);
	if (s == NULL) {
		printf("get custom socket failed\n");
		return TK_ERROR;
	}
	if (insert_custom_socket(gEnv.select_env, s)) {
		printf("insert_custom_socket failed\n");
		return TK_ERROR;
	}

	select_add_read_event(gEnv.select_env, s->event);
	s->type = CUSTOM_SOCKET_TYPE_INPUT;
	s->handler = hd_input_message;

	return TK_OK;
}

void clientmainloop(struct tk_client *cenv)
{
	int r = 0;
	
	fprintf(stderr, "message input:");
	while (1) {
		time_t t = time(NULL);
		struct tm* tmp_tm = localtime(&t);
		strftime(cache_str_time, sizeof(cache_str_time), "%F %H:%M:%S", tmp_tm);

		r = select_process_events(cenv->select_env, 1000);
		if (cenv->conn->failed || cenv->conn->finished) {
			elog("failed or finished");
			break;
		}
	}
}

static void usage()
{
	fprintf(stderr, "TODO\n");
	exit(0);
}

void parse_cmd_argv(struct tk_client *env, int argc, char **argv)
{
        int i;

        if (argc > 1) {
                for (i = 1; i < argc; i++) {
                        if (strcmp(argv[i], "-v") == 0) {
                                usage();
                                exit(1);
                        }
                        else if (strcmp(argv[i], "-i") == 0) {
                                if (i + 1 < argc) {
                                        env->clientid = atoi(argv[i+1]);
					i++;
                                        continue;
                                }
                        }
                        else if (strcmp(argv[i], "-n") == 0) {
				if (i + 1 < argc) {
                                        strcpy(env->clientname, argv[i+1]);
					i++;
					continue;
                                }
                        }
			else if (strcmp(argv[i], "-l") == 0) {
				if (i + 1 < argc) {
                                        strcpy(env->logpath, argv[i+1]);
					i++;
					continue;
                                }
			}

			usage();
                        exit(1);
		}
	}

	if (env->clientid <= 0) {
		fprintf(stderr, "clientid must bigger than 0!");
		exit(0);
	}
	if (strcmp(env->clientname, "")	== 0) {
		fprintf(stderr, "please set clientname!");
		exit(0);	
	}

	env->cinfo.clientid = env->clientid;
	strcpy(env->cinfo.clientname, env->clientname);
}

void show_conf(struct tk_client *env)
{
	fprintf(stderr, "clientid[%d] - clientname[%s]\n", env->clientid, env->clientname);
}

int main(int argc, char *argv[])
{
	
#if 0
	message msg;
	memset(&msg, 0x00, sizeof(msg));
	msg.groupid = 1;
	strcpy(msg.groupname, "hotmocha");
	msg.clientid  = 10;
	strcpy(msg.groupname, "hotmocha");
	strcpy(msg.content, "xxxx");
	int r = 0;
	struct tk_message tmsg;
	memset(&tmsg, 0x00, sizeof(tmsg));

	SERIAL_TO_TK_MESSAGE(&msg, &tmsg, message, MSG_TYPE_COMM_MSG, r);


	printf("aaa[%s]\n", tmsg.body);
return 0;
#endif
	setvbuf(stdout, NULL, _IONBF, 0);
	memset(&gEnv, 0x00, sizeof(gEnv));

	time_t t = time(NULL);
        struct tm* tmp_tm = localtime(&t);
        strftime(cache_str_time, sizeof(cache_str_time), "%F %H:%M:%S", tmp_tm);

	if (tk_read_conf_file(&gEnv)) {
		printf("read configure file failed\n");
		return 0;
	}
	strcpy(gEnv.logpath, "./client.log");

	parse_cmd_argv(&gEnv, argc, argv);

	FILE *log = fopen(gEnv.logpath, "a+");
	if (!log) {
		printf("open log file failed!");
		return 0;
	}
        setvbuf(log, NULL, _IOLBF, 0 );
	setlogfile(log);
	setloglevel(DEBUG);

	/* can use log system !! */

	if ((gEnv.select_env = create_select_env(after_connect_entry_impl)) == NULL) {
		elog("create select environment failed\n");	
		return 0;
	}
	elog("create select environment success!!!!!!");	

	if ((gEnv.conn = tk_connect_server(gEnv.select_env, gEnv.serverip, gEnv.serverport)) == NULL) {
		elog("connect server failed\n");
		return 0;
	}

	if (init_input_FD()) {
		elog("init input fd");
		return 0;
	}

	ilog("Client initialize success!");	

	fprintf(stderr, "Welcome to tk client!!\n");

	clientmainloop(&gEnv);

	return 0;
}
